package com.wwz.frame.controller;

import com.wwz.frame.task.AsyncTask;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * @Description 需要注意的问题一：异步方法的定义位置问题
 * 最好将异步调用的方法单独放在一个@Component类中，或者说不要将异步调用方法写在@Controller中，否则将无法进行调用，因为SpringBoot使用@Transaction需要经过事务拦截器，
 * 只有通过了该事务拦截器的方法才能被加入Spring的事务管理器中，而在同一个类中的一个方法调用另一个方法只会经过一次事务拦截器，
 * 所以如果是后面的方法使用了事务注解将不会生效，在这里异步调用也是同样的道理
 * 需要注意的问题二：异步方法的事务调用问题
 * 在@Async注解的方法上再使用@Transaction注解是无效的，在@Async注解的方法中调用Service层的事务方法是有效的
 * 需要注意的问题三：异步方法必须是实例的
 * 因为静态方法不能被override重写，因为@Async异步方法的实现原理是通过注入一个代理类到Bean中，该代理类集成这个Bean并且需要重写这个异步方法，所以需要是实例方法
 * @Author wwz
 * @Date 2019/09/24
 * @Param
 * @Return
 */
@RestController
@Slf4j
public class AsyncController {
    @Autowired
    private AsyncTask asyncTask;

    @RequestMapping(value = "/async", method = RequestMethod.GET)
    public String task() throws InterruptedException, ExecutionException {
        Long time = System.currentTimeMillis();
        Future<String> task1 = asyncTask.doTask1();
        Future<String> task2 = asyncTask.doTask2();
        while (true) {
            if (task1.isDone() && task2.isDone()) {
                log.info("Task1 result: {}", task1.get());
                log.info("Task2 result: {}", task2.get());
                break;
            }
            Thread.sleep(1000);
        }
        log.info("耗时:{} ms", System.currentTimeMillis() - time);
        return "success";
    }

}
